<?php

namespace App\Handlers;

use App\Models\AdTask;
use App\Models\Task;
use Encore\Admin\Config\ConfigModel;
use Illuminate\Database\Eloquent\Model;

class RedisHandler
{

    static public function saveModel(Model $model, $key)
    {
        $redis = app('redis');
        $redis->del([$key]);
        $redis->hmset($key, $model->toArray());
    }

    static public function syncTask(Task $task)
    {
        $redis = app('redis');
        $key = "dispatch:task:{$task->id}";

//        file_put_contents('observer.txt' , var_export('RedisHandler' , true),FILE_APPEND);

        if ($task->enable == 1 && $task->date == date('Y-m-d') && in_array($task->status, [TASK_STATUS_PENDING, TASK_STATUS_RUNNING])) {
            RedisHandler::saveModel($task, $key);
            $redis->hset($key, 'rate_type_data', \GuzzleHttp\json_encode($task->rateType));
        } else $redis->del([$key]);

        $rateData = \GuzzleHttp\json_decode($task->rateType->data);
        $rateDataSum = array_sum($rateData);
        foreach ($rateData as $hour => $hourValue) {
            $hourTaskKey = "dispatch:hour_task:$hour:{$task->id}";
            if ($task->enable == 1 && $task->date == date('Y-m-d') && in_array($task->status, [TASK_STATUS_PENDING, TASK_STATUS_RUNNING])) {
                $redis->hset($hourTaskKey, 'task_id', $task->id);
                $redis->hset($hourTaskKey, 'target_read_amount', ceil($task->target_read_amount * $hourValue / $rateDataSum));
                $redis->hset($hourTaskKey, 'target_like_amount', ceil($task->target_like_amount * $hourValue / $rateDataSum));
                $redis->hset($hourTaskKey, 'urls', $task->urls);
                $redis->hset($hourTaskKey, 'duration', $task->duration);
            } else {
                $redis->del([$hourTaskKey]);
            }
        }
//        file_put_contents('observer.txt' , var_export('end' , true),FILE_APPEND);
    }

    static public function syncTasks()
    {
        $redis = app('redis');
        $taskKeys = $redis->keys("dispatch:task:*");
        //将redis中的数据写入mysql
        foreach ($taskKeys as $taskKey) {
            $redisTask = $redis->hgetall($taskKey);
            if (!array_has($redisTask, 'id')) continue;
            $task = Task::find($redisTask['id']);
            if (empty($task)) continue;
            $task->valid_read_amount = array_get($redisTask, 'valid_read_amount', 0);
            $task->valid_like_amount = array_get($redisTask, 'valid_like_amount', 0);
            if ($task->valid_read_amount >= $task->target_read_amount
                && $task->valid_like_amount >= $task->target_like_amount) $task->status = TASK_STATUS_FINISHED;
            $task->save();
        }
        if ($taskKeys) $redis->del($taskKeys);//清空所有redis中的任务
        $tasks = Task::where('enable', 1)
            ->where('date', date('Y-m-d'))
            ->whereIn('status', [TASK_STATUS_PENDING, TASK_STATUS_RUNNING])
            ->get();
        $tasks->each(function ($task) use ($redis) {
            self::syncTask($task);
        });
    }

    static public function clearTaskDeviceLog()
    {
        $redis = app('redis');
        $deviceKeys = $redis->keys('dispatch:wx-user:*');
        if ($deviceKeys) $redis->del($deviceKeys);
    }

    static public function clearTask(Task $task)
    {
        $redis = app('redis');
        $rateData = \GuzzleHttp\json_decode($task->rateType->data);
        $hourTaskKeys = [];
        foreach ($rateData as $hour => $hourValue) {
            $hourTaskKeys[] = "dispatch:hour_task:$hour:{$task->id}";
        }
        if ($hourTaskKeys) $redis->del($hourTaskKeys);
        $redis->del(["dispatch:task:{$task->id}"]);
    }

    static public function clearHourTask()
    {
        $redis = app('redis');
        $hourTaskKeys = $redis->keys("dispatch:hour_task:*");
        if ($hourTaskKeys) $redis->del($hourTaskKeys);//清空所有redis中的分时任务
    }

    static public function syncAdTasks()
    {
        $redis = app('redis');
        $adTaskKeys = $redis->keys("ad:task:*");
        foreach ($adTaskKeys as $adTaskKey) {
            $redisAdTask = $redis->hgetall($adTaskKey);
            if (!array_has($redisAdTask, 'id')) continue;
            $adTask = AdTask::find($redisAdTask['id']);
            if (empty($adTask)) continue;
            $adTask->valid_read_amount = array_get($redisAdTask, 'valid_read_amount', 0);
            if ($adTask->current_read_amount >= $adTask->target_read_amount) $adTask->status = TASK_STATUS_FINISHED;
            $adTask->save();
        }
        if ($adTaskKeys) $redis->del($adTaskKeys);
        $adTasks = AdTask::where('enable', 1)
            ->whereIn('status', [TASK_STATUS_PENDING, TASK_STATUS_RUNNING])
            ->get();
        $adTasks->each(function ($adTask) {
            self::saveModel($adTask, "ad:task:{$adTask->id}");
        });
    }

    static public function clearAdTaskDeviceLog()
    {
        $redis = app('redis');
        $deviceKeys = $redis->keys('ad:device:*');
        $deviceRecordKeys = $redis->keys('ad:device-task-record:*');
        if ($deviceKeys) $redis->del($deviceKeys);
        if ($deviceRecordKeys) $redis->del($deviceRecordKeys);
    }

    static public function syncConfig()
    {
        $configs = ConfigModel::all();
        $configs->each(function ($config) {
            self::saveModel($config, "config:{$config->name}");
        });
    }

    static public function syncAppleTasks()
    {

        $redis = app('redis');
        $appleTaskKeys = $redis->keys("apple:task:*");
        foreach ($appleTaskKeys as $appleTaskKey) {
            $redisAppleTask = $redis->hgetall($appleTaskKey);
            if (!array_has($redisAppleTask, 'id')) continue;
            $appleTask = AppleTask::find($redisAppleTask['id']);
            if (empty($appleTask)) continue;
            //计算任务在线设备数
            $onlineDeviceLogKeys = $redis->keys("apple:online-device:*:" . $redisAppleTask['app_id']);
            $appleTask->current_running_device_amount = count($onlineDeviceLogKeys);
            //计算任务当前速率
            $appleTaskBuyLogKeys = $redis->keys("apple:buy-log:{$appleTask->app_id}");
            $appleTask->current_success_amount_of_one_minute = count($appleTaskBuyLogKeys);

            $appleTask->target_account_amount = $redisAppleTask['target_account_amount'];
            $appleTask->valid_account_amount = $redisAppleTask['valid_account_amount'];
            $appleTask->failed_account_amount = $redisAppleTask['failed_account_amount'];
            $appleTask->status = $redisAppleTask['status'];
            if ($appleTask->valid_account_amount >= $appleTask->target_account_amount) $appleTask->status = TASK_STATUS_FINISHED;
            $appleTask->save();
        }
        if ($appleTaskKeys) $redis->del($appleTaskKeys);
        $appleTasks = AppleTask::where('enable', 1)
            ->whereIn('status', [TASK_STATUS_PENDING, TASK_STATUS_RUNNING])
            ->get();
        $appleTasks->each(function ($appleTask) {
            self::saveModel($appleTask, "apple:task:{$appleTask->app_id}");
        });
    }

    static public function clearAppleTaskDeviceLog()
    {
        $redis = app('redis');
        $deviceKeys = $redis->keys('apple:device-record:*');
        if ($deviceKeys) $redis->del($deviceKeys);
    }

    static public function syncAppleDevices()
    {

        $redis = app('redis');
        $appleDeviceKeys = $redis->keys("apple:device:*");
        $apple_device_active_expire = config('apple_device_active_expire');
        foreach ($appleDeviceKeys as $appleDeviceKey) {
            $redisAppleDevice = $redis->hgetall($appleDeviceKey);
            if (!array_has($redisAppleDevice, 'id')) {
                $appleDevice = new AppleDevice();
                $appleDevice->name = $redisAppleDevice['name'];
                $appleDevice->version = $redisAppleDevice['version'];
            }
            else {
                $appleDevice = AppleDevice::find($redisAppleDevice['id']);
                if (empty($appleDevice)) {
                    $redis->del([$appleDeviceKey]);
                    continue;
                };
            }
            $appleDevice->success_amount = array_get($redisAppleDevice, 'success_amount', 0);
            $appleDevice->failed_amount = array_get($redisAppleDevice, 'failed_amount', 0);
            $appleDevice->last_active_time = $redisAppleDevice['last_active_time'];
            if (time() - strtotime($appleDevice->last_active_time) <= $apple_device_active_expire * 60) $appleDevice->status = 1;
            else $appleDevice->status = 2;
            $appleDevice->save();
        }
        if ($appleDeviceKeys) $redis->del($appleDeviceKeys);
        $appleDevices = AppleDevice::all();
        $appleDevices->each(function ($appleDevice) {
            self::saveModel($appleDevice, "apple:device:{$appleDevice->name}");
        });
    }

    static public function resetAppleDevices()
    {
        $redis = app('redis');
        $appleDeviceKeys = $redis->keys("apple:device:*");
        $redis->del($appleDeviceKeys);
        $appleDevice = new AppleDevice();
        \DB::table($appleDevice->getTable())->update([
            'success_amount' => 0,
            'failed_amount' => 0,
        ]);
        self::syncAppleDevices();
    }

    static public function syncAppleComments()
    {

        $redis = app('redis');
        $keys = $redis->keys("apple:comment:*");
        if ($keys) $redis->del($keys);
        $appleComments = AppleComments::where("enable", 1)->get();
        $appleComments->each(function ($model) {
            self::saveModel($model, "apple:comment:{$model->name}:{$model->id}");
        });
    }

    static public function syncAppleAccounts()
    {
        $redis = app('redis');
        $keys = $redis->keys("apple:active-account:*");
        $apple_account_active_expire = config('apple_account_active_expire');
        $activeAccounts = [];
        foreach ($keys as $redisKey) {
            $redisActiveAppleAccount = $redis->hgetall($redisKey);
            $appleAccount = AppleAccounts::where('email', $redisActiveAppleAccount['email'])->first();
            if (empty($appleAccount)) {
                $redis->del([$redisKey]);
                continue;
            };
            $appleAccount->success_task_amount = (int)array_get($redisActiveAppleAccount, 'success_task_amount', 0);
            $appleAccount->failed_task_amount = (int)array_get($redisActiveAppleAccount, 'failed_task_amount', 0);
            $appleAccount->status = $redisActiveAppleAccount['status'];
            //账号超出最大活跃时间则解除锁定
            if ($appleAccount->status == TASK_STATUS_RUNNING && time() - strtotime($redisActiveAppleAccount['last_active_time']) >= $apple_account_active_expire * 60) $appleAccount->status = TASK_STATUS_PENDING;
            $appleAccount->save();
            if ($appleAccount->status == TASK_STATUS_PENDING) $redis->del([$redisKey]);

            $activeAccounts[] = $redisActiveAppleAccount['email'];
        }
        $appleAccounts = AppleAccounts::where('status', 5)->get();
        $appleAccounts->each(function (AppleAccounts $model) use ($activeAccounts) {
            $key = "apple:account:{$model->email}";
            //不同步 活跃账号队列 中的数据
            if (!in_array($model->email, $activeAccounts)) self::saveModel($model, $key);
        });
    }

    static public function clearAppleAccounts()
    {
        $redis = app('redis');
        $keys = $redis->keys('apple:account:*');
        if ($keys) $redis->del($keys);
    }

    static public function syncAppleBuyLogs()
    {
        $redis = app('redis');
        $keys = $redis->keys("apple:buy-log:*");
        $redis_buy_log_expire = intval(config('redis_buy_log_expire'));
        $expired_at = strtotime("-$redis_buy_log_expire days");
        foreach ($keys as $redisKey) {
            $redisAppleBuyLog = $redis->hgetall($redisKey);
            if (array_has($redisAppleBuyLog, 'id')) {
                if (strtotime($redisAppleBuyLog['created_at']) <= $expired_at) {
                    $redis->del([$redisKey]);
                }
                continue;
            } else {
                $appleBuyLog = new AppleBuyLog();
                $appleBuyLog->fill($redisAppleBuyLog);
                $appleBuyLog->save();
                $redis->del([$redisKey]);
            }
        }
        $appleBuyLogs = AppleBuyLog::where('created_at', '>=', date('Y-m-d', $expired_at))->get();
        $appleBuyLogs->each(function (AppleBuyLog $model) {
            self::saveModel($model, "apple:buy-log:{$model->app_id}:{$model->account_email}:{$model->task_status}");
        });
    }
}